﻿#include "systemstate.h"
#include "common_log.h"

#include "componentmanager.h"
#include "idlestate.h"
#include "stopstate.h"
#include "workstate.h"

static SystemState* instance = nullptr;
SystemState* SystemState::GetInstance()
{
	if (instance == nullptr) {
		instance = new SystemState(nullptr);
	}

	return instance;
}

SystemState::SystemState(QObject *parent)
	: QObject(parent)
{
}

SystemState::~SystemState()
{
}

bool SystemState::Init()
{
	m_idle = new IdleState(this);
	if (m_idle->InitState()) {
		connect(m_idle, &SystemStateBase::ChangeSystemState, this, &SystemState::OnChangeSystemState);
	} else {
		log_error("idle state init failed");
		return false;
	}

	m_work = new WorkState(this);
	if (m_work->InitState()) {
		connect(m_work, &SystemStateBase::ChangeSystemState, this, &SystemState::OnChangeSystemState);
	} else {
		log_error("work state init failed");
		return false;
	}

	m_stop = new StopState(this);
	if (!m_stop->InitState()) {
		log_error("stop state init failed");
		return false;
	}
	connect(m_stop, &SystemStateBase::ChangeSystemState, this, &SystemState::OnChangeSystemState);
	connect(this, &SystemState::PublishSystemState, component, &ComponentManager::DealWithSystemEvent);
	return true;
}

void SystemState::SystemStart()
{
	m_currentState = SystemStateType::system_state_idle;
	if (!SystemReset()) {
		m_currentState = SystemStateType::system_state_stop;
	} else {
		if (!SystemCheck()) {
			m_currentState = SystemStateType::system_state_stop;
		} else {
			m_currentState = SystemStateType::system_state_work;
		}
	}
	this->Run();
	log_trace("System state change to {}", (int)m_currentState);
}

void SystemState::Run()
{
	log_trace("System state change to {}", (int)m_currentState);

	switch (m_currentState) {
	case SystemStateType::system_state_idle:
		m_idle->Running();
		break;
	case SystemStateType::system_state_work:
		m_work->Running();
		break;
	case SystemStateType::system_state_stop:
		m_stop->Running();
		break;
	default:
		break;
	}
	emit PublishSystemState((int)m_currentState);
}

void SystemState::Stop()
{
	switch (m_currentState) {
	case SystemStateType::system_state_idle:
		m_idle->SetStop();
		break;
	case SystemStateType::system_state_work:
		m_work->SetStop();
		break;
	case SystemStateType::system_state_stop:
		m_stop->SetStop();
		break;
	default:
		break;
	}
}

QString SystemState::GetCurrentStateStr()
{
	QString ret = "";
	switch (m_currentState) {
	case SystemStateType::system_state_idle:
		ret = u8"空闲状态";
		break;
	case SystemStateType::system_state_work:
		ret = u8"工作状态";
		break;
	case SystemStateType::system_state_stop:
		ret = u8"停止状态";
		break;
	default:
		ret = u8"未知状态";
		break;
	}

	return ret;
}


SystemStateType SystemState::GetCurrentState()
{
	return m_currentState;
}

void SystemState::OnChangeSystemState(int state)
{
	SystemStateType input = (SystemStateType)state;
	SystemStateType change = SystemStateType::system_state_stop;
	switch (input) {
	case SystemStateType::system_state_idle:
		if (!SystemReset()) {
			change = SystemStateType::system_state_stop;
		} else {
			change = SystemStateType::system_state_idle;
		}
		break;
	case SystemStateType::system_state_work:
		if (m_currentState != SystemStateType::system_state_idle) {
			return;
		}
		if (!SystemCheck()) {
			change = SystemStateType::system_state_stop;
		} else {
			change = SystemStateType::system_state_work;
		}
		break;
	case SystemStateType::system_state_stop:
		break;
	default:
		break;
	}

	if (m_currentState == change) {
		return;
	}
	this->Stop();
	m_currentState = change;
	m_writer.WriteTraceJournal(QString(u8"系统切换至%1").arg(GetCurrentStateStr()));
	this->Run();
}


bool SystemState::SystemReset()
{
	if (component->ResetComponent()) {
		m_writer.WriteTraceJournal("系统复位成功");
		return true;
	} else {
		m_writer.WriteErrorJournal("系统初始化,无法启动。失败原因：" + component->GetErrorMsg());
	}
	return false;
}
bool SystemState::SystemCheck()
{
	if (component->CheckComponent()) {
		m_writer.WriteTraceJournal("组件检查通过，切换工作状态");
		return true;
	} else {
		m_writer.WriteErrorJournal("组件异常：" + component->GetErrorMsg());
	}

	return false;
}
